﻿// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System;
using System.Collections;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml.Serialization;

namespace Microsoft.Build.Tasks.Deployment.ManifestUtilities
{
    /// <summary>
    /// Describes a manifest file reference.
    /// </summary>
    [ComVisible(false)]
    public sealed class FileReference : BaseReference
    {
        private ComClass[] _comClasses = null;
        private string _writeableType = null;
        private ProxyStub[] _proxyStubs = null;
        private TypeLib[] _typeLibs = null;

        /// <summary>
        /// Initializes a new instance of the FileReference class.
        /// </summary>
        public FileReference() : base()
        {
        }

        /// <summary>
        /// Initializes a new instance of the FileReference class.
        /// </summary>
        /// <param name="path">The specified source path of the file.</param>
        public FileReference(string path) : base(path)
        {
        }

        /// <summary>
        /// Specifies the set of COM classes referenced by the manifest for isolated applications and Reg-Free COM.
        /// </summary>
        [XmlIgnore]
        public ComClass[] ComClasses
        {
            get { return _comClasses; }
        }

        internal bool ImportComComponent(string path, OutputMessageCollection outputMessages, string outputDisplayName)
        {
            ComImporter importer = new ComImporter(path, outputMessages, outputDisplayName);
            if (importer.Success)
            {
                ArrayList list = new ArrayList();

                // Add TypeLib objects from importer...
                if (_typeLibs != null)
                    list.AddRange(_typeLibs);
                if (importer.TypeLib != null)
                    list.Add(importer.TypeLib);
                _typeLibs = (TypeLib[])list.ToArray(typeof(TypeLib));

                // Add ComClass objects from importer...
                list.Clear();
                if (_comClasses != null)
                    list.AddRange(_comClasses);
                if (importer.ComClasses != null)
                    list.AddRange(importer.ComClasses);
                _comClasses = (ComClass[])list.ToArray(typeof(ComClass));
            }
            return importer.Success;
        }

        /// <summary>
        /// Specifies whether the file is a data file.
        /// </summary>
        [XmlIgnore]
        public bool IsDataFile
        {
            get { return String.Compare(_writeableType, "applicationData", StringComparison.OrdinalIgnoreCase) == 0; }
            set { _writeableType = value ? "applicationData" : null; }
        }

        /// <summary>
        /// Specifies the set of proxy stubs referenced by the manifest for isolated applications and Reg-Free COM.
        /// </summary>
        [XmlIgnore]
        public ProxyStub[] ProxyStubs
        {
            get { return _proxyStubs; }
        }

        protected internal override string SortName
        {
            get { return TargetPath; }
        }

        /// <summary>
        /// Specifies the set of type libraries referenced by the manifest.
        /// </summary>
        [XmlIgnore]
        public TypeLib[] TypeLibs
        {
            get { return _typeLibs; }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlArray("ComClasses")]
        public ComClass[] XmlComClasses
        {
            get { return _comClasses; }
            set { _comClasses = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlArray("ProxyStubs")]
        public ProxyStub[] XmlProxyStubs
        {
            get { return _proxyStubs; }
            set { _proxyStubs = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlArray("TypeLibs")]
        public TypeLib[] XmlTypeLibs
        {
            get { return _typeLibs; }
            set { _typeLibs = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("WriteableType")]
        public string XmlWriteableType
        {
            get { return _writeableType; }
            set { _writeableType = value; }
        }

        #endregion
    }

    [ComVisible(false)]
    public class ComClass
    {
        private string _clsid;
        private string _description;
        private string _progid;
        private string _threadingModel;
        private string _tlbid;

        public ComClass()
        {
        }

        internal ComClass(Guid tlbId, Guid clsId, string progId, string threadingModel, string description)
        {
            _tlbid = tlbId.ToString("B");
            _clsid = clsId.ToString("B");
            _progid = progId;
            _threadingModel = threadingModel;
            _description = description;
        }

        [XmlIgnore]
        public string ClsId
        {
            get { return _clsid; }
        }

        [XmlIgnore]
        public string Description
        {
            get { return _description; }
        }

        [XmlIgnore]
        public string ProgId
        {
            get { return _progid; }
        }

        [XmlIgnore]
        public string ThreadingModel
        {
            get { return _threadingModel; }
        }

        [XmlIgnore]
        public string TlbId
        {
            get { return _tlbid; }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Clsid")]
        public string XmlClsId
        {
            get { return _clsid; }
            set { _clsid = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Description")]
        public string XmlDescription
        {
            get { return _description; }
            set { _description = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Progid")]
        public string XmlProgId
        {
            get { return _progid; }
            set { _progid = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("ThreadingModel")]
        public string XmlThreadingModel
        {
            get { return _threadingModel; }
            set { _threadingModel = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Tlbid")]
        public string XmlTlbId
        {
            get { return _tlbid; }
            set { _tlbid = value; }
        }

        #endregion
    }

    [ComVisible(false)]
    public class TypeLib
    {
        private string _flags;
        private string _helpDirectory;
        private string _resourceid;
        private string _tlbid;
        private string _version;

        public TypeLib()
        {
        }

        internal TypeLib(Guid tlbId, Version version, string helpDirectory, int resourceId, int flags)
        {
            _tlbid = tlbId.ToString("B");
            _version = version.ToString(2);
            _helpDirectory = helpDirectory;
            _resourceid = Convert.ToString(resourceId, 16);
            _flags = FlagsFromInt(flags);
        }

        [XmlIgnore]
        public string Flags
        {
            get { return _flags; }
        }

        private static string FlagsFromInt(int flags)
        {
            StringBuilder sb = new StringBuilder();
            if ((flags & 1) != 0)
                sb.Append("RESTRICTED,");
            if ((flags & 2) != 0)
                sb.Append("CONTROL,");
            if ((flags & 4) != 0)
                sb.Append("HIDDEN,");
            if ((flags & 8) != 0)
                sb.Append("HASDISKIMAGE,");
            return sb.ToString().TrimEnd(',');
        }

        [XmlIgnore]
        public string HelpDirectory
        {
            get { return _helpDirectory; }
        }

        [XmlIgnore]
        public string ResourceId
        {
            get { return _resourceid; }
        }

        [XmlIgnore]
        public string TlbId
        {
            get { return _tlbid; }
        }

        [XmlIgnore]
        public string Version
        {
            get { return _version; }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Flags")]
        public string XmlFlags
        {
            get { return _flags; }
            set { _flags = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("HelpDir")]
        public string XmlHelpDirectory
        {
            get { return _helpDirectory; }
            set { _helpDirectory = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("ResourceId")]
        public string XmlResourceId
        {
            get { return _resourceid; }
            set { _resourceid = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Tlbid")]
        public string XmlTlbId
        {
            get { return _tlbid; }
            set { _tlbid = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Version")]
        public string XmlVersion
        {
            get { return _version; }
            set { _version = value; }
        }

        #endregion
    }

    [ComVisible(false)]
    public class WindowClass
    {
        private string _name;
        private string _versioned;

        public WindowClass()
        {
        }

        public WindowClass(string name, bool versioned)
        {
            _name = name;
            _versioned = versioned ? "yes" : "no";
        }

        [XmlIgnore]
        public string Name
        {
            get { return _name; }
        }

        [XmlIgnore]
        public bool Versioned
        {
            get
            {
                if (String.Compare(_versioned, "yes", StringComparison.OrdinalIgnoreCase) == 0)
                    return true;
                if (String.Compare(_versioned, "no", StringComparison.OrdinalIgnoreCase) == 0)
                    return false;
                else
                    return true;
            }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Name")]
        public string XmlName
        {
            get { return _name; }
            set { _name = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Versioned")]
        public string XmlVersioned
        {
            get { return _versioned; }
            set { _versioned = value; }
        }

        #endregion
    }

    [ComVisible(false)]
    public class ProxyStub
    {
        private string _baseInterface;
        private string _iid;
        private string _name;
        private string _numMethods;
        private string _tlbid;

        public ProxyStub()
        {
        }

        [XmlIgnore]
        public string BaseInterface
        {
            get { return _baseInterface; }
        }

        [XmlIgnore]
        public string IID
        {
            get { return _iid; }
        }

        [XmlIgnore]
        public string Name
        {
            get { return _name; }
        }

        [XmlIgnore]
        public string NumMethods
        {
            get { return _numMethods; }
        }

        [XmlIgnore]
        public string TlbId
        {
            get { return _tlbid; }
        }

        #region " XmlSerializer "

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("BaseInterface")]
        public string XmlBaseInterface
        {
            get { return _baseInterface; }
            set { _baseInterface = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Iid")]
        public string XmlIID
        {
            get { return _iid; }
            set { _iid = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Name")]
        public string XmlName
        {
            get { return _name; }
            set { _name = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("NumMethods")]
        public string XmlNumMethods
        {
            get { return _numMethods; }
            set { _numMethods = value; }
        }

        [Browsable(false)]
        [EditorBrowsable(EditorBrowsableState.Never)]
        [XmlAttribute("Tlbid")]
        public string XmlTlbId
        {
            get { return _tlbid; }
            set { _tlbid = value; }
        }

        #endregion
    }
}
